﻿
using Nasty.Core.Entity;
using SqlSugar;
using System.Linq.Expressions;
using System;
using Nasty.Core.Model;
using System.Security.Principal;
using Force.DeepCloner;
using KellermanSoftware.CompareNetObjects;
using NetTaste;
using Nasty.Core.Attributes;
using Nasty.Core.Entity.System;
using System.Reflection;
using static System.Runtime.InteropServices.JavaScript.JSType;
using Nasty.Core.Session;
using Nasty.Core.Entity.Flow;

namespace Nasty.Core.SuperExtension
{
    public static class SqlSugarExtension
    {



        /// <summary>
        /// 创建，调用该方法尽量开启事务，因为Pre方法可能会进行仓储操作
        /// </summary>
        /// <param name="client"></param>
        /// <param name="entity"></param>
        public static void Add<T>(this SqlSugarClient client, T entity) where T : class, IBaseEntity, new()
        {
            BaseEntity<T>.TriggerNastyColumn(new T(), entity);

            entity.OnPreAdd();

            client.Insertable(entity).ExecuteCommand();
            //client.UpdateNav(entity).IncludesAllFirstLayer().ExecuteCommand();

            entity.OnAdded();
        }

        /// <summary>
        /// 批量创建，调用该方法尽量开启事务
        /// </summary>
        /// <param name="client"></param>
        /// <param name="entitys"></param>
        public static void Add<T>(this SqlSugarClient client, IEnumerable<T> entitys) where T : class, IBaseEntity, new()
        {
            foreach (var entity in entitys)
            {
                client.Add(entity);
            }
        }


        /// <summary>
        /// 批量创建，调用该方法尽量开启事务
        /// </summary>
        /// <param name="client"></param>
        /// <param name="entitys"></param>
        public static void Add<T>(this SqlSugarClient client, IEnumerable<ISaveModel> models) where T : class, IBaseEntity, new()
        {
            foreach (var model in models)
            {
                T? entity = null;
                entity = BaseEntity<T>.Merge(entity, model);
                if (entity != null) client.Add(entity);
            }
        }

        /// <summary>
        /// 修改，调用该方法尽量开启事务，因为Pre方法可能会进行仓储操作
        /// </summary>
        /// <param name="client"></param>
        /// <param name="entity"></param>
        /// <param name="isPre"></param>
        public static void Update<T>(this SqlSugarClient client, T entity, bool isPre = true) where T : class, IBaseEntity, new()
        {
            var old = client.Queryable<T>().InSingle(entity.Id);
            BaseEntity<T>.TriggerNastyColumn(old, entity);

            //触发修改事件
            if (isPre) entity.OnPreUpdate();

            ////获取需要更新的数据，空的数据不更新，避免覆盖
            //var data = entity.GetUpdateFields();
            ////进行更新
            //client.Updateable(data.Fields).AS(data.Table).WhereColumns("id").ExecuteCommand();

            client.Updateable(entity)
                .IgnoreColumns(ignoreAllNullColumns: true) //忽略空值
                .ExecuteCommand();

            if (isPre) entity.OnUpdated();
        }


        /// <summary>
        /// 批量修改，调用该方法尽量开启事务
        /// </summary>
        /// <param name="client"></param>
        /// <param name="entitys"></param>
        public static void Update<T>(this SqlSugarClient client, IEnumerable<T> entitys) where T : class, IBaseEntity, new()
        {
            foreach (var entity in entitys)
            {
                client.Update(entity);
            }
        }

        /// <summary>
        /// 修改，调用该方法尽量开启事务，因为Pre方法可能会进行仓储操作
        /// </summary>
        /// <param name="client"></param>
        /// <param name="entity"></param>
        /// <param name="isPre"></param>
        public static void Update<T>(this SqlSugarClient client, IEnumerable<ISaveModel> models) where T : class, IBaseEntity, new()
        {
            foreach (var model in models)
            {
                var entity = client.Queryable<T>().InSingle(model.Id);
                if (entity != null)
                {
                    entity = entity.Merge(model) as T;
                    if (entity != null) client.Update(entity);
                }
            }
        }

        /// <summary>
        /// 删除，调用该方法尽量开启事务，因为Pre方法可能会进行仓储操作
        /// </summary>
        /// <param name="client"></param>
        /// <param name="entity"></param>
        /// <param name="isLogic"></param>
        public static void Delete<T>(this SqlSugarClient client, T entity, bool isLogic = false) where T : class, IBaseEntity, new()
        {
            entity.OnPreDelete();

            if (isLogic)
            {
                //逻辑删除不触发Update事件,只触发Delete事件
                client.Update(entity, false);
            }
            else
            {
                client.DeleteableByObject(entity).ExecuteCommand();
            }

            entity.OnDeleted();
        }

        /// <summary>
        /// 删除，调用该方法尽量开启事务，因为Pre方法可能会进行仓储操作
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="client"></param>
        /// <param name="id"></param>
        /// <param name="isLogic"></param>
        public static void Delete<T>(this SqlSugarClient client, string id, bool isLogic = false) where T : class, IBaseEntity, new()
        {
            var entity = client.Query<T>(id);
            client.Delete(entity, isLogic);
        }

        /// <summary>
        /// 批量删除，调用该方法尽量开启事务
        /// </summary>
        /// <param name="client"></param>
        /// <param name="entitys"></param>
        /// <param name="isLogic"></param>
        public static void Delete<T>(this SqlSugarClient client, IEnumerable<T> entitys, bool isLogic = false) where T : class, IBaseEntity, new()
        {
            foreach (var entity in entitys)
            {
                client.Delete(entity, isLogic);
            }
        }

        /// <summary>
        /// 批量删除，调用该方法尽量开启事务
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="client"></param>
        /// <param name="ids"></param>
        /// <param name="isLogic"></param>
        public static void Delete<T>(this SqlSugarClient client, IEnumerable<string> ids, bool isLogic = false) where T : class, IBaseEntity, new()
        {
            var entitys = client.Query<T>(ids);
            foreach (var entity in entitys)
            {
                client.Delete(entity, isLogic);
            }
        }


        /// <summary>
        /// 查询
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="client"></param>
        /// <param name="id"></param>
        /// <returns></returns>
        public static T Query<T>(this SqlSugarClient client, string id) where T : class, IBaseEntity, new()
        {
            return client.Queryable<T>().InSingle(id);
        }

        /// <summary>
        /// 批量查询
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="client"></param>
        /// <param name="ids"></param>
        /// <returns></returns>

        public static IEnumerable<T> Query<T>(this SqlSugarClient client, IEnumerable<string> ids) where T : class, IBaseEntity, new()
        {
            return client.Queryable<T>().In((t) => t.Id, ids.ToArray()).ToList();
        }


        public static T? Save<T>(this SqlSugarClient client, ISaveModel model) where T : class, IBaseEntity, new()
        {
            if (string.IsNullOrEmpty(model.Id)) model.Id = SnowFlakeSingle.Instance.NextId().ToString();
            var obj = client.Queryable<T>().InSingle(model.Id);
            var data = BaseEntity<T>.Merge(obj, model);

            if (obj != null)
            {
                if (data != null) client.Update(data);
            }
            else
            {
                if (data != null) client.Add(data);
            }

            return data;
        }

        public static T? Save<T>(this SqlSugarClient client, IBaseEntity entity) where T : class, IBaseEntity, new()
        {
            if (string.IsNullOrEmpty(entity.Id)) entity.Id = SnowFlakeSingle.Instance.NextId().ToString();
            var obj = client.Queryable<T>().InSingle(entity.Id);
            var data = BaseEntity<T>.Merge(obj, entity);

            if (obj != null)
            {
                if (data != null) client.Update(data);
            }
            else
            {
                if (data != null) client.Add(data);
            }

            return data;
        }


        /// <summary>
        /// 限制创建部门查询
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="client"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static ISugarQueryable<T> AstrictDepartment<T>(this ISugarQueryable<T> client) where T : StandardEntity<T>, new()
        {
            var user = AppSession.CurrentUser.Value;
            if (user == null) throw new Exception("登录用户信息异常");

            var deptIds = user.Departments.Select(x => x.Id).ToList();
            return client.Where((t) => deptIds.Contains(t.CreateDeptId));
        }

        /// <summary>
        /// 限制创建人查询
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="client"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static ISugarQueryable<T> AstrictCreateUser<T>(this ISugarQueryable<T> client) where T : StandardEntity<T>, new()
        {
            var user = AppSession.CurrentUser.Value;
            if (user == null) throw new Exception("登录用户信息异常");

            var deptIds = user.Departments.Select(x => x.Id).ToList();
            return client.Where((t) => t.CreateUserId == user.Id);
        }

        /// <summary>
        /// 限制创建人或创建部门查询
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="client"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static ISugarQueryable<T> AstrictCreateUserOrDepartment<T>(this ISugarQueryable<T> client) where T : StandardEntity<T>, new()
        {
            var user = AppSession.CurrentUser.Value;
            if (user == null) throw new Exception("登录用户信息异常");

            var deptIds = user.Departments.Select(x => x.Id).ToList();
            return client.Where((t) => t.CreateUserId == user.Id || deptIds.Contains(t.CreateDeptId));
        }

        /// <summary>
        /// 限制流程审批人能查询，需要加载子对象FlowNode
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="client"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static ISugarQueryable<T> AstrictFlow<T>(this ISugarQueryable<T> client) where T : FlowEntity<T>, new()
        {
            var user = AppSession.CurrentUser.Value;
            if (user == null) throw new Exception("登录用户信息异常");
            return client.Where((t) => t.FlowNode.ApproverIds.Contains(user.Id));
        }

        /// <summary>
        /// 限制流程审批人或创建人或创建部门能查询，需要加载子对象FlowNode
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="client"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static ISugarQueryable<T> AstrictFlowOrCreateUserOrDepartment<T>(this ISugarQueryable<T> client) where T : FlowEntity<T>, new()
        {
            var user = AppSession.CurrentUser.Value;
            if (user == null) throw new Exception("登录用户信息异常");
            var deptIds = user.Departments.Select(x => x.Id).ToList();
            return client.Where((t) => t.CreateUserId == user.Id || deptIds.Contains(t.CreateDeptId) || t.FlowNode.ApproverIds.Contains(user.Id));
        }


        /// <summary>
        /// 限制指定部门人（包括创建部门）查询
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="client"></param>
        /// <param name="deptCodes"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static ISugarQueryable<T> AstrictDepartment<T>(this ISugarQueryable<T> client, List<string> deptCodes) where T : StandardEntity<T>, new()
        {
            var user = AppSession.CurrentUser.Value;
            if (user == null) throw new Exception("登录用户信息异常");

            var userDeptCodes = user.Departments.Select((x) => x.Code).ToList();
            var userDeptIds = user.Departments.Select(x => x.Id).ToList();
            var isAny = deptCodes.Count == 0 ? true : deptCodes.Intersect(userDeptCodes).Any();

            return client.Where((t) => userDeptIds.Contains(t.CreateDeptId) || isAny);

        }
        /// <summary>
        /// 限制指定部门人（包括创建部门）或创建人查询
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="client"></param>
        /// <param name="deptCodes"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static ISugarQueryable<T> AstrictDepartmentOrCreateUser<T>(this ISugarQueryable<T> client, List<string> deptCodes) where T : StandardEntity<T>, new()
        {
            var user = AppSession.CurrentUser.Value;
            if (user == null) throw new Exception("登录用户信息异常");

            var userDeptCodes = user.Departments.Select((x) => x.Code).ToList();
            var userDeptIds = user.Departments.Select(x => x.Id).ToList();
            var isAny = deptCodes.Count == 0 ? true : deptCodes.Intersect(userDeptCodes).Any();

            return client.Where((t) => userDeptIds.Contains(t.CreateDeptId) || isAny || t.CreateUserId == user.Id);
        }


        /// <summary>
        /// 限制流程审批人或创建人或创建部门或指定部门能查询，需要加载子对象FlowNode
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="client"></param>
        /// <param name="deptCodes"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static ISugarQueryable<T> AstrictFlowOrCreateUserOrDepartment<T>(this ISugarQueryable<T> client, List<string> deptCodes) where T : FlowEntity<T>, new()
        {
            var user = AppSession.CurrentUser.Value;
            if (user == null) throw new Exception("登录用户信息异常");

            var userDeptCodes = user.Departments.Select((x) => x.Code).ToList();
            var userDeptIds = user.Departments.Select(x => x.Id).ToList();
            var isAny = deptCodes.Count == 0 ? true : deptCodes.Intersect(userDeptCodes).Any();

            return client.Where((t) => isAny || t.CreateUserId == user.Id || userDeptIds.Contains(t.CreateDeptId) || t.FlowNode.ApproverIds.Contains(user.Id));
        }



        /// <summary>
        /// 限制指定角色查询
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="client"></param>
        /// <param name="deptCodes"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static ISugarQueryable<T> AstrictRole<T>(this ISugarQueryable<T> client, List<string> roleCodes) where T : StandardEntity<T>, new()
        {
            var user = AppSession.CurrentUser.Value;
            if (user == null) throw new Exception("登录用户信息异常");

            var isAny = roleCodes.Count == 0 ? true : roleCodes.Intersect(user.Roles).Any();
            return client.Where((t) => isAny);
        }

        /// <summary>
        /// 限制指定角色/创建人/创建部门查询
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="client"></param>
        /// <param name="deptCodes"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static ISugarQueryable<T> AstrictRoleOrDepartmentOrCreateUser<T>(this ISugarQueryable<T> client, List<string> roleCodes) where T : StandardEntity<T>, new()
        {
            var user = AppSession.CurrentUser.Value;
            if (user == null) throw new Exception("登录用户信息异常");
            var userDeptIds = user.Departments.Select(x => x.Id).ToList();
            var isAny = roleCodes.Count == 0 ? true : roleCodes.Intersect(user.Roles).Any();
            return client.Where((t) => isAny || t.CreateUserId == user.Id || userDeptIds.Contains(t.CreateDeptId));
        }

        /// <summary>
        /// 限制指定角色/创建人/创建部门/指定部门查询
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="client"></param>
        /// <param name="deptCodes"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static ISugarQueryable<T> AstrictRoleOrDepartmentOrCreateUser<T>(this ISugarQueryable<T> client, List<string> roleCodes, List<string> deptCodes) where T : StandardEntity<T>, new()
        {
            var user = AppSession.CurrentUser.Value;
            if (user == null) throw new Exception("登录用户信息异常");
            var userDeptIds = user.Departments.Select(x => x.Id).ToList();
            var isAnyRole = roleCodes.Count == 0 ? true : roleCodes.Intersect(user.Roles).Any();

            var userDeptCodes = user.Departments.Select((x) => x.Code).ToList();
            var isAnyDept = deptCodes.Count == 0 ? true : deptCodes.Intersect(userDeptCodes).Any();

            return client.Where((t) => isAnyRole || isAnyDept || t.CreateUserId == user.Id || userDeptIds.Contains(t.CreateDeptId));
        }

        /// <summary>
        /// 限制指定角色/创建人/创建部门/指定部门/审批人查询，需要加载子对象FlowNode
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="client"></param>
        /// <param name="deptCodes"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static ISugarQueryable<T> AstrictRoleOrDepartmentOrCreateUserOrFlow<T>(this ISugarQueryable<T> client, List<string> roleCodes, List<string> deptCodes) where T : FlowEntity<T>, new()
        {
            var user = AppSession.CurrentUser.Value;
            if (user == null) throw new Exception("登录用户信息异常");
            var userDeptIds = user.Departments.Select(x => x.Id).ToList();
            var isAnyRole = roleCodes.Count == 0 ? true : roleCodes.Intersect(user.Roles).Any();

            var userDeptCodes = user.Departments.Select((x) => x.Code).ToList();
            var isAnyDept = deptCodes.Count == 0 ? true : deptCodes.Intersect(userDeptCodes).Any();

            return client.Where((t) => isAnyRole || isAnyDept || t.CreateUserId == user.Id || userDeptIds.Contains(t.CreateDeptId) || t.FlowNode.ApproverIds.Contains(user.Id));
        }
    }
}
